package com.xiaoshuidi.cloud.module.rooms.utils;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;

@Slf4j
public class PdfUtils {
    private PdfUtils() {
    }

    private static Font font;
    private static Map<String, Font> fontCache = new ConcurrentHashMap<>(1);

    static {
        try {
            font = new Font(BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED));
            font.setSize(14);
        } catch (Exception ignore) {
        }
        String defaultFont = System.getProperty("pdfFont");
        if (StringUtils.isNotBlank(defaultFont)) {
            font = FontFactory.getFont(defaultFont,
                    BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 12, Font.NORMAL, BaseColor.BLACK);
        }
    }

    /**
     * 获取pdf中form表单的name
     * @param url
     * @return: java.lang.String[]
     */
    public static String[] getFieldName(String url){
        PdfReader reader = null;
        try {
            reader = new PdfReader(url);
            AcroFields s = reader.getAcroFields();
            Map<String, AcroFields.Item> fieldMap = s.getFields();
            return fieldMap.keySet().toArray(new String[0]);
        } catch (IOException e) {
            log.error("", e);
        }finally{
            if(null!=reader){
                reader.close();
            }
        }
        return new String[0];
    }

    public static PdfDoc newPdfDoc() {
        return new PdfDoc(PageSize.A4);
    }

    public static Font getFont() {
        return new Font(font.getBaseFont());
    }

    public static Font getFont(String fontFile) {
        fontCache.putIfAbsent(fontFile, FontFactory.getFont(fontFile,
                BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 12, Font.NORMAL, BaseColor.BLACK));
        return new Font(fontCache.get(fontFile).getBaseFont());
    }

    public static class PdfDoc {
        @Getter
        private Document doc;
        static float spacingBefore = 0;
        static float spacingAfter = 10;

        public PdfDoc(Rectangle rectangle) {
            doc = new Document(rectangle);
        }

        public PdfDoc open() {
            doc.open();
            return this;
        }

        public void close() {
            doc.close();
        }

        public static Paragraph paragraph(String text) {
            return paragraph(text, baseFont());
        }

        public static Paragraph paragraph(String text, Font font) {
            Paragraph p = new Paragraph(text, font);
            p.setSpacingBefore(spacingBefore);
            p.setSpacingAfter(spacingAfter);
            return p;
        }

        public static Font baseFont() {
            return new Font(font.getBaseFont());
        }

        public PdfDoc addParagraph(String text) throws DocumentException {
            Paragraph p = paragraph(text);
            doc.add(p);
            return this;
        }

        public PdfDoc addTable(int column, Consumer<Table> consumer) throws DocumentException {
            Table t = new Table(column);
            consumer.accept(t);
            doc.add(t.table);
            t.table.deleteBodyRows();
            return this;
        }
    }

    public static class Table {
        PdfPTable table;

        public Table(int column) {
            table = new PdfPTable(column);
        }

        public Table options(Consumer<PdfPTable> consumer) {
            consumer.accept(table);
            return this;
        }

        public Table addCell(String text, int colspan) {
            return addCell(text, colspan, PdfDoc.baseFont());
        }

        public Table addCell(String text, int colspan, Font font) {
            return addCell(text, colspan, font, cell -> {
            });
        }

        public Table addCell(String text, int colspan, Font font, int horizontalAlignment) {
            return addCell(text, colspan, font, cell -> {
                cell.setColspan(colspan);
                cell.setHorizontalAlignment(horizontalAlignment);
            });
        }

        public Table addCell(String text, int colspan, int horizontalAlignment) {
            return addCell(text, colspan, PdfDoc.baseFont(), cell -> {
                cell.setColspan(colspan);
                cell.setHorizontalAlignment(horizontalAlignment);
            });
        }

        public Table addCell(String text, int colspan, Font font, Consumer<PdfPCell> consumer) {
            Cell c = new Cell();
            c.addParagraph(text, font)
                    .options(cell -> {
                        cell.setColspan(colspan);
                        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                        consumer.accept(cell);
                    });
            table.addCell(c.cell);
            return this;
        }

        public Table addCell(String text) {
            return addCell(text, 1, PdfDoc.baseFont(), cell -> {
                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                cell.setPaddingBottom(6);
            });
        }

        public Table addCell(String text, Consumer<PdfPCell> consumer) {
            Cell c = new Cell();
            c.addParagraph(text, font)
                    .options(cell -> {
                        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                        consumer.accept(cell);
                    });
            table.addCell(c.cell);
            return this;
        }

        public Table addCell(String... text) {
            for (String s : text) {
                addCell(s);
            }
            return this;
        }

        public Table addCell(Table table) {
            PdfPCell cell = new PdfPCell(table.table);
            cell.setColspan(this.table.getNumberOfColumns());
            this.table.addCell(cell);
            return this;
        }
    }

    public static class Cell {
        PdfPCell cell = new PdfPCell();

        public Cell options(Consumer<PdfPCell> consumer) {
            cell.setPaddingBottom(5);
            consumer.accept(cell);
            return this;
        }

        public Cell addParagraph(String text) {
            Paragraph p = PdfDoc.paragraph(text);
            cell.setPhrase(p);
            return this;
        }

        public Cell addParagraph(String text, Font font) {
            Paragraph p = PdfDoc.paragraph(text, font);
            cell.setPhrase(p);
            return this;
        }
    }

    /**
     * @description: 查询PDF关键字（返回找到的第一个的坐标）
     * @param filepath
     * @param keyWords
     * @return: float[]
     */
    public static float[] getKeyWordsByPath(String filepath, String keyWords) {
        float[] coordinate = null;
        PdfReader pdfReader = null;
        try{
            pdfReader = new PdfReader(filepath);
            coordinate = getKeyWords(pdfReader, keyWords);
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(null!=pdfReader){
                pdfReader.close();
            }
        }
        return coordinate;
    }

    /**
     * 查找关键字
     * @param pdfReader
     * @param keyWords
     * @return: float[]
     */
    private static float[] getKeyWords(PdfReader pdfReader, String keyWords) {
        float[] coordinate = null;
        int page = 0;
        try{
            int pageNum = pdfReader.getNumberOfPages();
            PdfReaderContentParser pdfReaderContentParser = new PdfReaderContentParser(pdfReader);
            CustomRenderListener renderListener = new CustomRenderListener();
            renderListener.setKeyWord(keyWords);
            for (page = 1; page <= pageNum; page++) {
                renderListener.setPage(page);
                pdfReaderContentParser.processContent(page, renderListener);
                coordinate = renderListener.getPcoordinate();
                if (coordinate != null) break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return coordinate;
    }

}
